/*
 * @Author:  wangbing198
 * @Date: 2020-10-21 10:33:01
 * @LastEditTime: 2020-11-11 15:26:32
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /crowd-funding/src/modules/anthem.core.js
 */
import 'core-js/es6/map'
import 'core-js/es6/set'
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import createStore from './store'
import { isObject } from '@jmfe/jm-common'
import * as sagaEffects from 'redux-saga/effects'
import { combineReducers } from 'redux'
import invariant from 'invariant'

// module 中的固有 key
const REDUCER_KEY = 'reducer'
const SAGA_KEY = 'saga'
/**
 * 判断是不是dom
 * @param {*} node
 * @returns
 */
function isHTMLElement(node) {
	return (
		typeof node === 'object' &&
		node !== null &&
		node.nodeType &&
		node.nodeName
	)
}
function handleModules(modules) {
	// 聚合所有的 reducer saga
	return modules.reduce(
		(root, module) => {
			if (module[REDUCER_KEY] && isObject(module[REDUCER_KEY])) {
				root[REDUCER_KEY] = {
					...root[REDUCER_KEY],
					...module[REDUCER_KEY]
				}
			}
			if (module[SAGA_KEY]) {
				root[SAGA_KEY].push(sagaEffects.fork(module[SAGA_KEY]))
			}
			return root
		},
		// module 初始值
		{ [REDUCER_KEY]: {}, [SAGA_KEY]: [] }
	)
}
function getReducer(reducer) {
	return combineReducers(reducer)
}

function getSaga(sagas) {
	return function*() {
		yield sagaEffects.all(sagas)
	}
}
class Anthme {
	constructor() {
		// 存储 modules
		this._modules = []
		// redux store 实例
		this.store = null
	}

	addModule(module) {
		const objFlag = isObject(module)
		invariant(objFlag, 'Module is not Object')
		if (objFlag) {
			this._modules.push(module)
		}
	}

	addExports(exports) {
		const objFlag = isObject(exports)
		invariant(objFlag, 'Exports is not Object')
		if (objFlag) {
			// export object
			Object.keys(exports).forEach(item => {
				this.addModule(exports[item])
			})
		}
	}

	start(App, $root) {
		invariant(isHTMLElement($root), 'start root is not HTMLElement')
		const store = this.getStore()
		this.store = store
		render(
			<Provider store={store}>
				<App />
			</Provider>,
			$root
		)
	}

	getStore() {
		const modules = handleModules(this._modules)
		return createStore(
			{},
			getReducer(modules[REDUCER_KEY]),
			getSaga(modules[SAGA_KEY])
		)
	}
}

export default Anthme
